﻿using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace Nirvana
{
    [CustomEditor(typeof(AnimatorOptimizer))]
    public class AnimatorOptimizerEditor : Editor
    {
        private SerializedProperty exposedTransforms;
        private SerializedProperty searchPatterns;
        private ReorderableList exposedlist;
        private ReorderableList searchlist;
        private GUIContent[] _guicontents;

        public override void OnInspectorGUI()
        {
            base.serializedObject.Update();
            this.exposedlist.DoLayoutList();
            this.searchlist.DoLayoutList();
            base.serializedObject.ApplyModifiedProperties();

            AnimatorOptimizer animatorOptimizer = (AnimatorOptimizer)this.target;
            Animator animator = animatorOptimizer.GetComponent<Animator>();
            if (animator == null)
            {
                EditorGUILayout.HelpBox("This GameObject does not have Animator.", MessageType.Warning);
                return;
            }
            if (animator.avatar == null)
            {
                EditorGUILayout.HelpBox("This Animator does not have an avatar.", MessageType.Warning);
                return;
            }
            GUILayout.BeginHorizontal();
            GUI.enabled = (this.searchPatterns.arraySize > 0);
            if (GUILayout.Button("Search Parttern", new GUILayoutOption[0]))
            {
                this.SearchExposed(animatorOptimizer.transform);
            }
            GUI.enabled = true;
            if (GUILayout.Button("Clear", new GUILayoutOption[0]))
            {
                this.Clear();
            }
            GUILayout.EndHorizontal();

            if (!animator.hasTransformHierarchy)
            {
                if (GUILayout.Button("Revert"))
                {
                    animatorOptimizer.Deoptimize();
                }
            }
            else if (GUILayout.Button("Optimize"))
            {
                animatorOptimizer.Optimize();
            }
        }

        private void OnEnable()
        {
            AnimatorOptimizer animatorOptimizer = (AnimatorOptimizer)this.target;
            if (animatorOptimizer == null)
            {
                return;
            }
            List<string> _exposedlist = new List<string>();
            List<string> _searchlist = new List<string>();
            MatchRegex(_exposedlist, _searchlist, animatorOptimizer.transform);

            this._guicontents = new GUIContent[_exposedlist.Count];
            int num = 0;
            foreach (string text in _exposedlist)
            {
                this._guicontents[num] = new GUIContent(text);
                num++;
            }

            this.exposedTransforms = serializedObject.FindProperty("exposedTransforms");
            this.searchPatterns = serializedObject.FindProperty("searchPatterns");
            this.exposedlist = new ReorderableList(serializedObject, this.exposedTransforms);
            this.exposedlist.drawHeaderCallback = DrawHeaderEnter;
            this.exposedlist.elementHeight = EditorGUIUtility.singleLineHeight;
            this.exposedlist.drawElementCallback = DrawElement;
            this.exposedlist.onAddDropdownCallback = OnAddDropdownCallback;
            this.exposedlist.onRemoveCallback = OnRemoveCallback;

            this.searchlist = new ReorderableList(serializedObject, this.searchPatterns);
            this.searchlist.drawHeaderCallback = DrawHeaderSearch;
            this.searchlist.elementHeightCallback = OnElementHeightCallback;
            this.searchlist.drawElementCallback = DrawElementSearch;
        }

        private void DrawHeaderEnter(Rect rect)
        {
            GUI.Label(rect, "Extra Transforms to Expose", EditorStyles.label);
        }
        private void DrawHeaderSearch(Rect rect)
        {
            GUI.Label(rect, "Search Pattern", EditorStyles.label);
        }

        private void DrawElement( Rect rect, int index, bool isActive, bool isFocused)
        {
            SerializedProperty arrayElementAtIndex = this.exposedTransforms.GetArrayElementAtIndex(index);
            string stringValue = arrayElementAtIndex.stringValue;
            string text = stringValue.Substring(stringValue.LastIndexOf("/") + 1);
            GUI.Label(rect, text, EditorStyles.label);
        }

        private void OnAddDropdownCallback(Rect rect, ReorderableList list)
        {
            EditorUtility.DisplayCustomMenu(rect, this._guicontents, -1, (object userData, string[] options, int selected) => {
                string text = options[selected];
                this.SetExposed(text);

            }, null);
        }

        private void OnRemoveCallback(ReorderableList list)
        {
            this.exposedTransforms.DeleteArrayElementAtIndex(list.index);
        }

        private void SetExposed(string txt)
        {
            for (int i = 0; i < this.exposedTransforms.arraySize; i++)
            {
                SerializedProperty arrayElementAtIndex = this.exposedTransforms.GetArrayElementAtIndex(i);
                string stringValue = arrayElementAtIndex.stringValue;
                if (stringValue == txt)
                {
                    return;
                }
            }
            base.serializedObject.Update();
            this.exposedTransforms.InsertArrayElementAtIndex(this.exposedTransforms.arraySize);
            SerializedProperty arrayElementAtIndex2 = this.exposedTransforms.GetArrayElementAtIndex(this.exposedTransforms.arraySize - 1);
            arrayElementAtIndex2.stringValue = txt;
            base.serializedObject.ApplyModifiedProperties();
        }
        private float OnElementHeightCallback(int index)
        {
            SerializedProperty arrayElementAtIndex = this.searchPatterns.GetArrayElementAtIndex(index);
            return EditorGUI.GetPropertyHeight(arrayElementAtIndex);
        }

        internal void DrawElementSearch(Rect rect, int index, bool isActive, bool isFocused)
        {
            SerializedProperty arrayElementAtIndex = this.searchPatterns.GetArrayElementAtIndex(index);
            EditorGUI.PropertyField(rect, arrayElementAtIndex, GUIContent.none);
        }



        private void SearchExposed(Transform root)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < this.searchPatterns.arraySize; i++)
            {
                SerializedProperty arrayElementAtIndex = this.searchPatterns.GetArrayElementAtIndex(i);
                string stringValue = arrayElementAtIndex.stringValue;
                if (!string.IsNullOrEmpty(stringValue))
                {
                    Regex regex = new Regex(stringValue);
                    this.MatchRegex(list, root, regex);
                    list.Clear();
                }
            }
        }
        private void MatchRegex(List<string> list, Transform node, Regex regex)
        {
            list.Add(node.name);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < list.Count; i++)
            {
                stringBuilder.Append(list[i]);
                if (i < list.Count - 1)
                {
                    stringBuilder.Append('/');
                }
            }
            string text = stringBuilder.ToString();
            if (regex.IsMatch(text))
            {
                this.MatchSuccess(text);
            }
            foreach (object obj in node)
            {
                Transform transform = (Transform)obj;
                this.MatchRegex(list, transform, regex);
            }
            list.RemoveAt(list.Count - 1);
        }

        private void MatchSuccess(string txt)
        {
            for (int i = 0; i < this.exposedTransforms.arraySize; i++)
            {
                SerializedProperty arrayElementAtIndex = this.exposedTransforms.GetArrayElementAtIndex(i);
                string stringValue = arrayElementAtIndex.stringValue;
                if (stringValue == txt)
                {
                    return;
                }
            }
            base.serializedObject.Update();
            this.exposedTransforms.InsertArrayElementAtIndex(this.exposedTransforms.arraySize);
            SerializedProperty arrayElementAtIndex2 = this.exposedTransforms.GetArrayElementAtIndex(this.exposedTransforms.arraySize - 1);
            arrayElementAtIndex2.stringValue = txt;
            base.serializedObject.ApplyModifiedProperties();
        }

        private void Clear()
        {
            base.serializedObject.Update();
            this.exposedTransforms.ClearArray();
            base.serializedObject.ApplyModifiedProperties();
        }

        private void MatchRegex(List<string> list1, List<string> list2, Transform node)
        {
            list2.Add(node.name);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < list2.Count; i++)
            {
                stringBuilder.Append(list2[i]);
                if (i < list2.Count - 1)
                {
                    stringBuilder.Append('/');
                }
            }
            list1.Add(stringBuilder.ToString());

            foreach (object obj in node)
            {
                Transform transform = (Transform)obj;
                this.MatchRegex(list1, list2, transform);
            }
            list2.RemoveAt(list2.Count - 1);
        }

    }
}

